import sys, os, json
from pathlib import Path
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QLabel, QPushButton, QToolBar,
    QVBoxLayout, QHBoxLayout, QWidget, QFileDialog, QSizePolicy,
    QSlider, QCheckBox, QScrollArea, QMessageBox, QGridLayout,
    QSplitter, QTreeWidget, QTreeWidgetItem, QMenuBar, QAbstractItemView,
    QTreeView
)
from PyQt6.QtGui import QPixmap, QIcon, QAction, QColor, QStandardItemModel, QStandardItem
from PyQt6.QtCore import Qt, QSize, QAbstractItemModel, QModelIndex, QVariant

# pip install pillow pyqt6
# export QT_QPA_PLATFORM=xcb

# 定义一个树形结构的节点类
class TreeItem:
    def __init__(self, data, parent=None):
        """
        初始化树节点
        
        参数:
            data: 节点存储的数据，可以是单个值或元组(用于多列数据)
            parent: 父节点引用，默认为None(表示根节点)
        """
        self.parent_item = parent  # 父节点
        self.item_data = data      # 节点存储的数据
        self.child_items = []      # 子节点列表
        
    def append_child(self, child):
        """添加子节点"""
        self.child_items.append(child)
        
    def child(self, row):
        """
        获取指定行的子节点
        
        参数:
            row: 子节点索引
            
        返回:
            子节点对象，如果索引无效则返回None
        """
        if row < 0 or row >= len(self.child_items):
            return None
        return self.child_items[row]
    
    def child_count(self):
        """返回子节点数量"""
        return len(self.child_items)
    
    def column_count(self):
        """返回节点支持的列数(固定为2列)"""
        return 2
    
    def data(self, column):
        """
        获取节点在指定列的数据
        
        参数:
            column: 列索引(0或1)
            
        返回:
            列数据，如果列索引无效返回None
            
        说明:
            - 如果数据是元组，第0列返回第一个元素，第1列返回第二个元素
            - 如果数据不是元组，第0列返回数据本身，第1列在有子节点时返回空字符串，否则返回数据本身
        """
        if column == 0:
            return self.item_data[0] if isinstance(self.item_data, tuple) else str(self.item_data)
        elif column == 1:
            if isinstance(self.item_data, tuple):
                return self.item_data[1]
            return "" if self.child_count() > 0 else str(self.item_data)
        return None
    
    def set_data(self, column, value):
        """
        设置节点在指定列的数据
        
        参数:
            column: 列索引(0或1)
            value: 要设置的值
            
        返回:
            bool: 设置成功返回True，失败返回False
        """
        if column == 0:
            if isinstance(self.item_data, tuple):
                self.item_data = (value, self.item_data[1])
            else:
                self.item_data = value
            return True
        elif column == 1:
            if isinstance(self.item_data, tuple):
                self.item_data = (self.item_data[0], value)
            else:
                self.item_data = value
            return True
        return False
    
    def parent(self):
        """返回父节点"""
        return self.parent_item
    
    def row(self):
        """
        返回当前节点在父节点中的行索引
        
        返回:
            如果是根节点返回0，否则返回在父节点子列表中的索引
        """
        if self.parent_item:
            return self.parent_item.child_items.index(self)
        return 0

# 继承自QAbstractItemModel的自定义树模型
class TreeModel(QAbstractItemModel):
    def __init__(self, data, parent=None):
        """
        初始化树模型
        
        参数:
            data: 要展示的原始数据(字典或列表)
            parent: 父对象
        """
        super().__init__(parent)
        # 创建根节点，包含两列标题("Key", "Value")
        self.root_item = TreeItem(("Key", "Value"))
        # 设置模型数据
        self.setup_model_data(data, self.root_item)
    
    def setup_model_data(self, data, parent):
        """
        递归设置模型数据
        
        参数:
            data: 要处理的数据(字典或列表)
            parent: 父节点
        """
        if isinstance(data, dict):
            # 处理字典类型数据
            for key, value in data.items():
                if isinstance(value, (dict, list)):
                    # 如果值是嵌套结构，创建子节点并递归处理
                    item = TreeItem(key, parent)
                    parent.append_child(item)
                    self.setup_model_data(value, item)
                else:
                    # 简单值直接创建节点
                    parent.append_child(TreeItem((key, value), parent))
        elif isinstance(data, list):
            # 处理列表类型数据
            for i, value in enumerate(data):
                if isinstance(value, (dict, list)):
                    # 如果元素是嵌套结构，创建子节点并递归处理
                    item = TreeItem(str(i), parent)
                    parent.append_child(item)
                    self.setup_model_data(value, item)
                else:
                    # 简单值直接创建节点
                    parent.append_child(TreeItem((str(i), value), parent))
    
    def index(self, row, column, parent=QModelIndex()):
        """
        创建并返回与给定行、列和父节点对应的模型索引
        
        参数:
            row: 行号
            column: 列号
            parent: 父索引
            
        返回:
            创建的模型索引，如果无效则返回空索引
        """
        if not self.hasIndex(row, column, parent):
            return QModelIndex()
        
        parent_item = self.get_item(parent)
        child_item = parent_item.child(row)
        if child_item:
            return self.createIndex(row, column, child_item)
        return QModelIndex()
    
    def parent(self, index):
        """
        返回给定索引的父索引
        
        参数:
            index: 子节点索引
            
        返回:
            父节点索引，如果是根节点则返回空索引
        """
        if not index.isValid():
            return QModelIndex()
        
        child_item = self.get_item(index)
        parent_item = child_item.parent()
        
        if parent_item == self.root_item:
            return QModelIndex()
        
        return self.createIndex(parent_item.row(), 0, parent_item)
    
    def rowCount(self, parent=QModelIndex()):
        """
        返回父节点下的行数(子节点数)
        
        参数:
            parent: 父节点索引
            
        返回:
            子节点数量
        """
        parent_item = self.get_item(parent)
        return parent_item.child_count()
    
    def columnCount(self, parent=QModelIndex()):
        """
        返回列数(固定为2列)
        
        参数:
            parent: 父节点索引(未使用)
            
        返回:
            列数(2)
        """
        return 2
    
    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        """
        返回索引处数据
        
        参数:
            index: 模型索引
            role: 数据角色
            
        返回:
            请求的数据，如果无效则返回空QVariant
        """
        if not index.isValid():
            return QVariant()
        
        # 只处理显示和编辑角色
        if role != Qt.ItemDataRole.DisplayRole and role != Qt.ItemDataRole.EditRole:
            return QVariant()
        
        item = self.get_item(index)
        return item.data(index.column())
    
    def setData(self, index, value, role=Qt.ItemDataRole.EditRole):
        """
        设置索引处数据
        
        参数:
            index: 模型索引
            value: 要设置的值
            role: 数据角色
            
        返回:
            bool: 设置成功返回True，否则返回False
        """
        if role != Qt.ItemDataRole.EditRole:
            return False
        
        item = self.get_item(index)
        result = item.set_data(index.column(), value)
        
        if result:
            # 数据改变时发出信号
            self.dataChanged.emit(index, index)
        
        return result
    
    def get_item(self, index):
        """
        获取索引对应的内部项
        
        参数:
            index: 模型索引
            
        返回:
            对应的TreeItem对象，如果无效则返回根节点
        """
        if index.isValid():
            item = index.internalPointer()
            if item:
                return item
        return self.root_item
    
    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        """
        返回表头数据
        
        参数:
            section: 列号
            orientation: 方向(水平/垂直)
            role: 数据角色
            
        返回:
            表头数据，如果无效则返回空QVariant
        """
        if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole:
            return self.root_item.data(section)
        return QVariant()
    
    def flags(self, index):
        """
        返回索引处的标志
        
        参数:
            index: 模型索引
            
        返回:
            项标志的组合
        """
        if not index.isValid():
            return Qt.ItemFlag.NoItemFlags
        
        # 第二列设置为可编辑
        if index.column() == 1:
            return super().flags(index) | Qt.ItemFlag.ItemIsEditable
        return super().flags(index)
    
    def get_data(self):
        """
        获取模型数据(递归转换为原始数据结构)
        
        返回:
            转换后的字典或列表
        """
        return self._get_data_from_item(self.root_item)
    
    def _get_data_from_item(self, item):
        """
        递归从TreeItem转换为原始数据结构
        
        参数:
            item: 当前处理的TreeItem
            
        返回:
            转换后的字典或列表
        """
        if item.child_count() == 0:
            return None
        
        first_child = item.child(0)
        # 根据第一个子节点判断是字典结构还是列表结构
        is_dict = isinstance(first_child.item_data, tuple)
        
        if is_dict:
            result = {}
            for i in range(item.child_count()):
                child = item.child(i)
                key = child.data(0)
                if child.child_count() > 0:
                    value = self._get_data_from_item(child)
                else:
                    value = child.data(1)
                result[key] = value
            return result
        else:
            result = []
            for i in range(item.child_count()):
                child = item.child(i)
                if child.child_count() > 0:
                    value = self._get_data_from_item(child)
                else:
                    value = child.data(1)
                result.append(value)
            return result

# 自定义的树形视图控件，继承自QTreeView
class LWFQTreeView(QTreeView):
    def __init__(self):
        super().__init__()  # 调用父类构造函数
        
        # 初始化示例数据（嵌套字典结构）
        self.sample_data = {
            "个人信息": {
                "姓名": "张三",
                "年龄": 30,
                "联系方式": {
                    "手机": "123456789",
                    "邮箱": "zhangsan@example.com"
                }
            },
            "工作信息": {
                "公司": ["ABC公司", "DEF公司"],  # 列表数据示例
                "职位": "工程师",
                "部门": "研发部"
            }
        }
        
        # 创建树模型并设置数据
        self.model = TreeModel(self.sample_data)
        self.setModel(self.model)  # 将模型绑定到视图
        
        # 设置视图行为：
        self.setSelectionBehavior(QTreeView.SelectionBehavior.SelectRows)  # 整行选择
        # 设置编辑触发方式：双击或按下编辑键
        self.setEditTriggers(QTreeView.EditTrigger.DoubleClicked | QTreeView.EditTrigger.EditKeyPressed)
        
        # 连接点击信号到槽函数
        self.clicked.connect(self.on_item_clicked)
    
    def refresh_data(self, data=None):
        """
        刷新视图数据
        
        参数:
            data: 新数据，如果为None则使用示例数据
        """
        if data is None:
            data = self.sample_data
        else:
            self.sample_data = data
        # 创建新模型并设置
        self.model = TreeModel(data)
        self.setModel(self.model)
        self.expandAll()  # 展开所有节点
    
    def get_selected_data(self):
        """
        获取当前选中项的数据并显示信息框
        
        如果没有选中项，则显示提示信息
        """
        index = self.currentIndex()  # 获取当前选中项的索引
        if not index.isValid():  # 检查索引是否有效
            QMessageBox.information(self, "信息", "请先选择一个项目")
            return
        
        # 获取选中项的数据
        item = self.model.get_item(index)
        key = item.data(0)  # 第一列数据（键）
        value = item.data(1)  # 第二列数据（值）
        
        # 构建选中项的完整路径
        path = []
        current = item
        # 向上遍历父节点直到根节点
        while current.parent() and current.parent() != self.model.root_item:
            current = current.parent()
            path.insert(0, current.data(0))  # 在列表开头插入父节点名称
        
        # 将路径转换为字符串表示
        path_str = " -> ".join(path + [key]) if path else key
        
        # 显示包含完整路径和键值的信息框
        QMessageBox.information(
            self, 
            "选中数据", 
            f"路径: {path_str}\n键: {key}\n值: {value}"
        )
    
    def get_all_data(self):
        """获取模型中的所有数据并更新sample_data"""
        self.sample_data = self.model.get_data()  # 更新示例数据
        return self.sample_data
    
    def on_item_clicked(self, index):
        """
        点击项时的槽函数
        
        参数:
            index: 被点击项的模型索引
        """
        if index.column() == 0:  # 只处理第一列的点击
            item = self.model.get_item(index)
            key = item.data(0)
            value = item.data(1)
            print(f"选中: {key} = {value}")  # 在控制台打印选中信息
    
    def closeEventAccept(self, state):
        """
        关闭前的检查函数
        
        返回:
            bool: 如果数据已修改且用户选择不退出，返回True；否则返回False
        """
        current_data = self.model.get_data()  # 获取当前模型数据
        data = state.copy()
        data["image_files"] = {}
        for i in range(len(state["image_files"])):
            data["image_files"][str(i)] = state["image_files"][i]
        # 检查数据是否被修改
        if current_data != data:
            # 弹出确认对话框
            reply = QMessageBox.question(
                self, '未保存的更改', 
                '数据已修改但未保存。确定要退出吗?',
                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
            )
            if reply == QMessageBox.StandardButton.No:
                return False  # 取消关闭
        return True # 允许关闭

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("图片浏览器")
        self.setGeometry(100, 100, 800, 600)
        
        # 初始化变量
        self.image_dir = ""
        self.image_files = []
        self.current_index = -1
        self.scale_factor = 1.0
        self.max_size = 2000  # 最大显示尺寸
        self.min_size = 100   # 最小显示尺寸
        self.fit_to_window = True  # 是否适应窗口大小

        # 初始化UI
        self.init_ui()

    def init_ui(self):

        # 创建文件动作、菜单、工具栏
        self.create_file_menu_toolbar()

        # 创建图片动作、菜单、工具栏
        self.create_image_menu_toolbar()

        # 创建帮助动作、菜单、工具栏
        self.create_help_menu_toolbar()

        # 创建图片显示部分
        self.create_central_widget()

        # 状态栏
        self.status_bar = self.statusBar()
        self.status_bar.showMessage("请选择包含图片的目录")

    def create_file_menu_toolbar(self):
        # 文件菜单
        self.menu_file = self.menuBar().addMenu("文件(&F)")
        # 文件工具栏
        self.toolbar_file = QToolBar("文件工具栏")
        self.toolbar_file.setMovable(True)
        self.addToolBar(self.toolbar_file)

        # 适应窗口
        self.fit_checkbox = self.add_checkbox_qaction(
            "icons/适应窗口.png",
            "适应窗口",
            "适应窗口复选框",
            self.fit_to_window,
            self.toggle_fit_to_window,
            self.menu_file,
            self.toolbar_file
        )
        # 目录选择按钮
        self.add_general_qaction(
            "icons/选择目录.png",
            "选择目录",
            "目录选择按钮",
            self.select_directory,
            self.menu_file,
            self.toolbar_file
        )
        # 保存状态按钮
        self.add_general_qaction(
            "icons/保存状态.png",
            "保存状态",
            "保存状态按钮",
            self.save_state,
            self.menu_file,
            self.toolbar_file
        )
        # 加载状态按钮
        self.add_general_qaction(
            "icons/加载状态.png",
            "加载状态",
            "加载状态按钮",
            self.load_state,
            self.menu_file,
            self.toolbar_file
        )
        # 退出动作
        self.add_general_qaction(
            "icons/退出.png",
            "退出",
            "退出应用程序",
            self.close,
            self.menu_file
        )

    def create_image_menu_toolbar(self):
        # 图片菜单
        self.menu_image = self.menuBar().addMenu("图片(&I)")
        # 图片工具栏
        self.toolbar_image = QToolBar("图片工具栏")
        self.toolbar_image.setMovable(True)
        self.addToolBar(self.toolbar_image)
        # 上一张按钮
        self.prev_button = self.add_general_qaction(
            "icons/上一张.png",
            "上一张",
            "上一张按钮",
            self.show_previous_image,
            self.menu_image,
            self.toolbar_image
        )
        # 下一张按钮
        self.next_button = self.add_general_qaction(
            "icons/下一张.png",
            "下一张",
            "下一张按钮",
            self.show_next_image,
            self.menu_image,
            self.toolbar_image
        )
        # 尺寸滑动条
        self.size_slider = QSlider(Qt.Orientation.Horizontal)
        self.size_slider.setRange(self.min_size, self.max_size)
        self.size_slider.setValue(self.max_size)
        self.size_slider.setTickInterval(100)
        self.size_slider.setSingleStep(50)
        self.size_slider.valueChanged.connect(self.update_image_size)
        self.toolbar_image.addWidget(self.size_slider)
        # 显示当前尺寸的标签
        self.size_label = QLabel(f"{self.max_size}px")
        self.toolbar_image.addWidget(self.size_label)
        # 放大按钮
        self.add_general_qaction(
            "icons/放大按钮.png",
            "放大 (+)",
            "放大按钮",
            self.zoom_in,
            self.menu_image,
            self.toolbar_image
        )
        # 缩小按钮
        self.add_general_qaction(
            "icons/缩小按钮.png",
            "缩小 (-)",
            "缩小按钮",
            self.zoom_out,
            self.menu_image,
            self.toolbar_image
        )
        # 重置按钮
        self.add_general_qaction(
            "icons/重置按钮.png",
            "重置",
            "重置按钮",
            self.reset_zoom,
            self.menu_image,
            self.toolbar_image
        )
        
    def create_help_menu_toolbar(self):
        # 帮助菜单
        help_menu = self.menuBar().addMenu("帮助(&H)")
        # 关于动作
        about_action = QAction(QIcon(), "关于(&A)", self)
        about_action.setStatusTip("关于本程序")
        about_action.triggered.connect(self._show_about_dialog)
        help_menu.addAction(about_action)
    
    def create_central_widget(self):
        # 图片显示标签
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.image_label.setSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Ignored)
        
        # 使用布局来管理图片标签
        image_layout = QVBoxLayout()
        image_layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
        image_layout.setContentsMargins(0, 0, 0, 0)
        image_layout.addWidget(self.image_label)
        
        # 图片显示区域
        self.image_container = QWidget()
        self.image_container.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
        self.image_container.setLayout(image_layout)
        
        # 使用QScrollArea作为图片容器
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.scroll_area.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
        self.scroll_area.setWidget(self.image_container)
        
        # 创建左侧面板
        left_panel = QWidget()
        #left_panel.setFixedWidth(300)  # 设置固定宽度为200像素
        left_panel.setMinimumWidth(200)
        left_panel.setMaximumWidth(500)
        left_layout = QGridLayout(left_panel)
        # 创建树视图
        self.tree_view = LWFQTreeView()
        left_layout.addWidget(self.tree_view)
        
        # 创建分割器（实现可移动的分隔条）
        splitter = QSplitter()
        #splitter.resize(300, 500)

        # 创建主布局
        main_layout = QGridLayout()
        main_layout.addWidget(splitter, 0, 0)

        # 将左右面板添加到分割器中
        splitter.addWidget(left_panel)
        splitter.addWidget(self.scroll_area)

        # 主窗口部件
        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)
        
    def add_general_qaction(self, icon, text, tip, connect, menu=None, toolbar=None):
        general_qaction = QAction(QIcon(icon), text, self)
        general_qaction.setStatusTip(tip)
        general_qaction.triggered.connect(connect)
        if menu:
            menu.addAction(general_qaction)
        if toolbar:
            toolbar.addAction(general_qaction)
        return general_qaction
    
    def add_checkbox_qaction(self, icon, text, tip, checked, connect, menu=None, toolbar=None):
        checkbox_qaction = QAction(QIcon(icon), text, self)
        checkbox_qaction.setStatusTip(tip)
        checkbox_qaction.setCheckable(True)
        checkbox_qaction.setChecked(checked)
        checkbox_qaction.toggled.connect(connect)
        if menu:
            menu.addAction(checkbox_qaction)
        if toolbar:
            toolbar.addAction(checkbox_qaction)
        return checkbox_qaction
    
    def onclick(self):
        print("onclick")
    
    def onclick_checkbox(self, checked):
        if checked:
            print(checked)
    
    def toggle_fit_to_window(self, state):
        """切换适应窗口模式"""
        self.fit_to_window = state
        #self.show_image()
    
    def update_image_size(self, value):
        """更新图片显示尺寸"""
        self.size_label.setText(f"{value}px")
        if not self.fit_to_window:
            self.show_image()
    
    def select_directory(self):
        """选择图片目录"""
        dir_path = QFileDialog.getExistingDirectory(self, "选择图片目录")
        if dir_path:
            self.image_dir = dir_path
            self.load_images()
    
    def load_images(self):
        """加载目录中的图片文件"""
        # 支持的图片格式
        supported_formats = (
            ".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff", ".webp"
        )
        
        # 获取目录中的图片文件
        image_files = [
            os.path.join(self.image_dir, f) for f in os.listdir(self.image_dir)
            if f.lower().endswith(supported_formats)
        ]
        self.image_files = sorted(image_files)
        
        if not self.image_files:
            self.status_bar.showMessage("目录中没有找到支持的图片文件")
            self.current_index = -1
            self.image_label.clear()
            """ self.prev_button.setEnabled(False)
            self.next_button.setEnabled(False) """
            return
        
        self.current_index = 0
        self.show_image()
        """ self.prev_button.setEnabled(True)
        self.next_button.setEnabled(True) """
        self.status_bar.showMessage(f"已加载 {len(self.image_files)} 张图片")
    
    def show_image(self):
        """显示当前索引的图片"""
        if self.current_index < 0 or self.current_index >= len(self.image_files):
            return
            
        image_path = self.image_files[self.current_index]
        pixmap = QPixmap(image_path)
        
        if pixmap.isNull():
            self.status_bar.showMessage(f"无法加载图片: {image_path}")
            return
        
        # 获取滚动区域的可视区域尺寸
        viewport_size = self.scroll_area.viewport().size()
        available_width = max(viewport_size.width() - 20, 10)  # 确保最小值
        available_height = max(viewport_size.height() - 20, 10)  # 确保最小值
        
        # 计算目标尺寸
        if self.fit_to_window:
            # 计算适合窗口的尺寸，保持宽高比
            img_width = pixmap.width()
            img_height = pixmap.height()
            
            # 计算适合窗口的缩放比例
            width_ratio = available_width / img_width if img_width > 0 else 1.0
            height_ratio = available_height / img_height if img_height > 0 else 1.0
            scale_ratio = min(width_ratio, height_ratio, 1.0)  # 不放大超过原图
            
            target_width = int(img_width * scale_ratio)
            target_height = int(img_height * scale_ratio)
        else:
            # 使用滑动条指定的尺寸
            target_size = self.size_slider.value()
            # 计算保持宽高比的尺寸
            img_ratio = pixmap.width() / max(pixmap.height(), 1)  # 避免除以0
            
            if pixmap.width() > pixmap.height():
                target_width = target_size
                target_height = int(target_size / img_ratio)
            else:
                target_height = target_size
                target_width = int(target_size * img_ratio)
        
        # 应用缩放
        scaled_pixmap = pixmap.scaled(
            target_width,
            target_height,
            Qt.AspectRatioMode.KeepAspectRatio,
            Qt.TransformationMode.SmoothTransformation
        )
        
        self.image_label.setPixmap(scaled_pixmap)
        self.image_label.setMinimumSize(QSize(target_width, target_height))
        
        # 更新滚动区域
        self.image_container.setMinimumSize(QSize(target_width, target_height))
        self.image_container.adjustSize()
        
        self.status_bar.showMessage(f"正在显示: {os.path.basename(image_path)} - {target_width}×{target_height}")
    
    def show_next_image(self):
        """显示下一张图片"""
        if self.current_index < len(self.image_files) - 1:
            self.current_index += 1
            self.show_image()
    
    def show_previous_image(self):
        """显示上一张图片"""
        if self.current_index > 0:
            self.current_index -= 1
            self.show_image()
    
    def zoom_in(self):
        """放大图片"""
        if self.fit_to_window:
            self.fit_to_window = False
            self.fit_checkbox.setChecked(False)
        
        current_size = self.size_slider.value()
        new_size = min(current_size + 50, self.max_size)
        self.size_slider.setValue(new_size)
    
    def zoom_out(self):
        """缩小图片"""
        if self.fit_to_window:
            self.fit_to_window = False
            self.fit_checkbox.setChecked(False)
        
        current_size = self.size_slider.value()
        new_size = max(current_size - 50, self.min_size)
        self.size_slider.setValue(new_size)
    
    def reset_zoom(self):
        """重置缩放"""
        self.fit_to_window = True
        self.fit_checkbox.setChecked(True)
        self.size_slider.setValue(self.max_size)
        self.show_image()
    
    def save_state(self):
        """保存当前状态到JSON文件"""
        if not self.image_dir or not self.image_files:
            self.status_bar.showMessage("没有可保存的状态")
            return
            
        # 获取相对路径（如果可能）
        image_files = []
        if hasattr(self, 'base_dir'):
            # 如果设置了基准目录，保存相对路径
            for f in self.image_files:
                rel_path = os.path.relpath(f, self.base_dir)
                image_files.append(rel_path)
        else:
            # 否则保存绝对路径
            image_files = self.image_files.copy()
        
        state = {
            'image_dir': self.image_dir,
            'image_files': image_files,
            'current_index': self.current_index,
            'fit_to_window': self.fit_to_window,
            'scale_factor': self.scale_factor,
            'max_size': self.max_size,
            'min_size': self.min_size,
            'size_slider_value': self.size_slider.value()
        }
        
        # 刷新显示
        data = state.copy()
        data["image_files"] = [Path(item).name for item in data["image_files"]]
        self.tree_view.refresh_data(data)
        
        # 获取JSON文件保存路径
        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存状态", "", "JSON Files (*.json)"
        )
        
        if file_path:
            try:
                # 确保文件以.json结尾
                if not file_path.lower().endswith('.json'):
                    file_path += '.json'
                
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump(state, f, ensure_ascii=False, indent=4)
                
                self.status_bar.showMessage(f"状态已保存到 {file_path}")
            except Exception as e:
                self.status_bar.showMessage(f"保存状态时出错: {str(e)}")
    
    def load_state(self):
        """从JSON文件加载状态"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "加载状态", "", "JSON Files (*.json)"
        )
        
        if file_path:
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    state = json.load(f)
                
                # 恢复状态
                self.image_dir = state['image_dir']
                self.image_files = state['image_files']
                self.current_index = state['current_index']
                self.fit_to_window = state['fit_to_window']
                self.scale_factor = state['scale_factor']
                self.max_size = state['max_size']
                self.min_size = state['min_size']
                
                # 更新UI元素
                self.fit_checkbox.setChecked(self.fit_to_window)
                self.size_slider.setValue(state['size_slider_value'])
                self.size_label.setText(f"{state['size_slider_value']}px")
                
                # 检查图片文件路径是否是相对路径
                if any(os.path.isfile(os.path.join(self.image_dir, f)) for f in self.image_files):
                    # 路径是相对的，转换为绝对路径
                    self.image_files = [os.path.join(self.image_dir, f) for f in self.image_files]
                
                # 显示图片
                if self.image_files and self.current_index < len(self.image_files):
                    self.show_image()
                    self.prev_button.setEnabled(True)
                    self.next_button.setEnabled(True)
                    self.status_bar.showMessage(f"状态已从 {file_path} 加载")
                else:
                    self.status_bar.showMessage("加载的状态无效或图片文件不存在")
                    self.reset_state()

                # 刷新显示
                data = state.copy()
                data["image_files"] = [Path(item).name for item in data["image_files"]]
                self.tree_view.refresh_data(data)
                    
            except Exception as e:
                self.status_bar.showMessage(f"加载状态时出错: {str(e)}")
                self.reset_state()
    
    def reset_state(self):
        """重置所有状态到初始值"""
        self.image_dir = ""
        self.image_files = []
        self.current_index = -1
        self.fit_to_window = True
        self.fit_checkbox.setChecked(True)
        self.size_slider.setValue(self.max_size)
        self.size_label.setText(f"{self.max_size}px")
        self.image_label.clear()
        self.prev_button.setEnabled(False)
        self.next_button.setEnabled(False)
        self.status_bar.showMessage("状态已重置")
    
    def _show_about_dialog(self):
        QMessageBox.about(
            self,
            "关于",
            "<h2>PyQt6 菜单示例</h2>"
            "<p>这是一个演示 PyQt6 菜单功能的示例程序。</p>"
            "<p>版本 1.0.0</p>"
            "<p>© 2023 示例公司</p>"
            "<br>"
            "<p>适应窗口：图片尺寸适应软件界面大小。</p>"
            "<p>选择目录：选择图片所在的目录，根据名称排序。</p>"
            "<p>保存状态：保存当前的浏览信息到json文件。</p>"
            "<p>加载状态：从json文件加载保存的浏览状态。</p>"
            "<p>图片工具：上一张、下一张、尺寸滑条、放大、缩小和重置尺寸。</p>"
        )
    
    def closeEvent(self, event):
        image_files = [Path(item).name for item in self.image_files]
        state = {
            'image_dir': self.image_dir,
            'image_files': image_files,
            'current_index': self.current_index,
            'fit_to_window': self.fit_to_window,
            'scale_factor': self.scale_factor,
            'max_size': self.max_size,
            'min_size': self.min_size,
            'size_slider_value': self.size_slider.value()
        }
        # 关闭前检查是否有未保存的更改
        if self.tree_view.closeEventAccept(state):
            event.accept()
        else:
            event.ignore()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    viewer = MainWindow()
    viewer.show()
    sys.exit(app.exec())